﻿
using System.Web;

namespace KharaPos.Web.Services
{
    using System;
    using System.Data;
    using System.Linq;
    using System.ServiceModel.DomainServices.EntityFramework;
    using System.ServiceModel.DomainServices.Hosting;
    using KharaPos.Web.Entities;


    /// <summary>
    /// The catalog service is used for managing a catalog of products within 
    /// the system. Items within the catalog can be made available to multiple
    /// business units.
    /// </summary>
    [EnableClientAccess()]
    public class CatalogService : LinqToEntitiesDomainService<KharaPosDataContext>
    {

        /// <summary>
        /// Retrieves the <see cref="BusinessUnit"/>defined in the system.
        /// </summary>
        /// <returns></returns>
        public IQueryable<BusinessUnit> GetBusinessUnits()
        {
            return this.ObjectContext.BusinessUnits;
        }

        /// <summary>
        /// Adds a <see cref="BusinessUnit"/> to the System.
        /// </summary>
        /// <param name="businessUnit"></param>
        public void InsertBusinessUnit(BusinessUnit businessUnit)
        {
            if ((businessUnit.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(businessUnit, EntityState.Added);
            }
            else
            {
                this.ObjectContext.BusinessUnits.AddObject(businessUnit);
            }
        }

        /// <summary>
        /// Updates information about an existing <see cref="BusinessUnit"/>.
        /// </summary>
        /// <param name="currentBusinessUnit"></param>
        public void UpdateBusinessUnit(BusinessUnit currentBusinessUnit)
        {
            this.ObjectContext.BusinessUnits.AttachAsModified(currentBusinessUnit, ChangeSet.GetOriginal(currentBusinessUnit));
        }

        /// <summary>
        /// Removes a <see cref="BusinessUnit"/>
        /// </summary>
        /// <param name="businessUnit"></param>
        public void DeleteBusinessUnit(BusinessUnit businessUnit)
        {
            if ((businessUnit.EntityState == EntityState.Detached))
            {
                ObjectContext.BusinessUnits.Attach(businessUnit);
            }
            this.ObjectContext.BusinessUnits.DeleteObject(businessUnit);
        }

        public IQueryable<CatalogDetail> GetCatalogDetails()
        {
            return this.ObjectContext.CatalogDetails;
        }

        public void InsertCatalogDetail(CatalogDetail catalogDetail)
        {
            if ((catalogDetail.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(catalogDetail, EntityState.Added);
            }
            else
            {
                this.ObjectContext.CatalogDetails.AddObject(catalogDetail);
            }
        }

        public void UpdateCatalogDetail(CatalogDetail currentCatalogDetail)
        {
            this.ObjectContext.CatalogDetails.AttachAsModified(currentCatalogDetail, this.ChangeSet.GetOriginal(currentCatalogDetail));
        }

        public void DeleteCatalogDetail(CatalogDetail catalogDetail)
        {
            if ((catalogDetail.EntityState == EntityState.Detached))
            {
                this.ObjectContext.CatalogDetails.Attach(catalogDetail);
            }
            this.ObjectContext.CatalogDetails.DeleteObject(catalogDetail);
        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<Category> GetCategories()
        {
            return this.ObjectContext.Categories;
        }

        public void InsertCategory(Category category)
        {
            if ((category.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(category, EntityState.Added);
            }
            else
            {
                this.ObjectContext.Categories.AddObject(category);
            }
        }

        public void UpdateCategory(Category currentCategory)
        {
            this.ObjectContext.Categories.AttachAsModified(currentCategory, this.ChangeSet.GetOriginal(currentCategory));
        }

        public void DeleteCategory(Category category)
        {
            if ((category.EntityState == EntityState.Detached))
            {
                this.ObjectContext.Categories.Attach(category);
            }
            this.ObjectContext.Categories.DeleteObject(category);
        }

        public IQueryable<CatalogEntry> GetCatalogEntries()
        {
            return ObjectContext.CatalogEntries;
        }

        public void InsertCatalogEntry(CatalogEntry catalogEntry)
        {
            if (catalogEntry.EntityState != EntityState.Detached)
            {
                ObjectContext.ObjectStateManager.ChangeObjectState(catalogEntry, EntityState.Added);
            }
            else
            {
                ObjectContext.CatalogEntries.AddObject(catalogEntry);
            }
        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<Product> GetProducts()
        {
            return this.ObjectContext.Products;
        }

        public void InsertProduct(Product product)
        {
            if ((product.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(product, EntityState.Added);
            }
            else
            {
                this.ObjectContext.Products.AddObject(product);
            }
        }

        public void UpdateProduct(Product currentProduct)
        {
            this.ObjectContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct));
        }

        public void DeleteProduct(Product product)
        {
            if ((product.EntityState == EntityState.Detached))
            {
                this.ObjectContext.Products.Attach(product);
            }
            this.ObjectContext.Products.DeleteObject(product);
        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<Upc> GetUpcs()
        {
            return this.ObjectContext.Upcs;
        }

        public void InsertUpc(Upc upc)
        {
            if ((upc.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(upc, EntityState.Added);
            }
            else
            {
                this.ObjectContext.Upcs.AddObject(upc);
            }
        }

        public void UpdateUpc(Upc currentUpc)
        {
            this.ObjectContext.Upcs.AttachAsModified(currentUpc, this.ChangeSet.GetOriginal(currentUpc));
        }

        public void DeleteUpc(Upc upc)
        {
            if ((upc.EntityState == EntityState.Detached))
            {
                this.ObjectContext.Upcs.Attach(upc);
            }
            this.ObjectContext.Upcs.DeleteObject(upc);
        }

        public void StoreBusinessUnit(BusinessUnit bu)
        {
            HttpContext.Current.Session[bu.GetType().FullName + bu.Id] = bu;
        }

        public void CatalogProductForBusinessUnit(Product product, int businessUnitId)
        {
            var currentBu = (BusinessUnit)HttpContext.Current.
                Session[typeof(BusinessUnit).FullName + businessUnitId];
            //Use the stored retrieved BusinessUnit Here.
            var entry = ObjectContext.CreateObject<CatalogEntry>();
            entry.BusinessUnitId = businessUnitId;
            entry.ProductId = product.Id;
            entry.DateAdded = DateTime.Now;
            ObjectContext.CatalogEntries.AddObject(entry);
            ObjectContext.SaveChanges();
        }

        public IQueryable<Product> GetProductsAvailableForCurrentBu(int businessUnitId)
        {
            //var currentBuId = (int)HttpContext.Current.Session["CurrentBu"];
            return from product in ObjectContext.Products
                   let entries = from entry in product.Catalogs
                                 where entry.BusinessUnitId == businessUnitId
                                 select entry
                   where entries.Count() == 0
                   select product;

        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<ManuFacturer> GetManuFacturers()
        {
            return this.ObjectContext.ManuFacturers;
        }

        public void InsertManuFacturer(ManuFacturer manuFacturer)
        {
            if ((manuFacturer.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(manuFacturer, EntityState.Added);
            }
            else
            {
                this.ObjectContext.ManuFacturers.AddObject(manuFacturer);
            }
        }

        public void UpdateManuFacturer(ManuFacturer currentManuFacturer)
        {
            this.ObjectContext.ManuFacturers.AttachAsModified(currentManuFacturer, this.ChangeSet.GetOriginal(currentManuFacturer));
        }

        public void DeleteManuFacturer(ManuFacturer manuFacturer)
        {
            if ((manuFacturer.EntityState == EntityState.Detached))
            {
                this.ObjectContext.ManuFacturers.Attach(manuFacturer);
            }
            this.ObjectContext.ManuFacturers.DeleteObject(manuFacturer);
        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<ProductSale> GetProductSales()
        {
            return this.ObjectContext.ProductSales;
        }

        // TODO: Consider
        // 1. Adding parameters to this method and constraining returned results, and/or
        // 2. Adding query methods taking different parameters.
        public IQueryable<Sale> GetSales()
        {
            return this.ObjectContext.Sales;
        }


    }
}
